package com.yzi.core.thread
{
	import flash.events.Event;
	import flash.events.TimerEvent;
	import flash.utils.Dictionary;
	import flash.utils.Timer;

	public class Thread implements IRunnable
	{
		static private const NAME:String = "Thread";
		
		static private const g_table:Dictionary = new Dictionary(true);
		static private const g_list:Vector.<Thread> = new Vector.<Thread>();
		static private const g_executor:Timer = new Timer(Thread.Millisecond, 1);
		static private const g_invokerList:Vector.<Function> = new Vector.<Function>();
		
		static public var CurrentThread:Thread;
		static public var Millisecond:uint = 1;
		
		protected var m_runnable:IRunnable;
		
		protected var m_interrupt:Boolean;
		protected var m_stop:Boolean;
		protected var m_delegator:IRunnable;
		protected var m_delay:uint;
		
		protected var m_name:String;
		
		public function Thread($runnable:IRunnable=null)
		{
			super();
			m_runnable = $runnable;
			if(!m_runnable) m_runnable = this;
			
			init();
		}
		
		private function init(): void
		{
			g_list.push(this);
			SetName(NAME+g_list.length);
			g_table[GetName()] = this;
			g_invokerList.push(onTick);
		}
		
		protected function onTick(event:Event): void
		{
			event.target.removeEventListener(TimerEvent.TIMER, onTick );
			if(m_interrupt) throw new Error("interrupt");
			if(m_stop) return ;
			CurrentThread = this;
			m_runnable.Run();
		}
		
		public function Start(): void
		{
			if(m_interrupt) {
				throw new Error("interrupt");
				return ;
			}
			g_executor.reset();
			g_executor.addEventListener(TimerEvent.TIMER, onTick );
			if(g_executor.delay != Millisecond) g_executor.delay = Millisecond;
			g_executor.start();
			m_stop = false;
		}
		
		public function Stop(): void
		{
			g_executor.stop();
			m_stop = true;
		}
		
		public function Interrupt(): void
		{
			g_executor.stop();
			m_stop = m_interrupt = true;
		}		
		
		[Abstract]
		public function Run(): void
		{
			
		}
		
		public function Destory(): void
		{
			if(g_executor) g_executor.removeEventListener(TimerEvent.TIMER, onTick );
			g_invokerList.splice(g_invokerList.indexOf(onTick),1);
			g_executor.stop();
			
			g_table[GetName()] = null;
			delete g_table[GetName()]; 
			var index:int = g_list.indexOf(this);
			if(index > -1) g_list.splice(index,1);
			if(CurrentThread == this) CurrentThread = null;
		}
		
		static public function Kill(): void {
			for each(var invoker:Function in g_invokerList) {
				g_executor.removeEventListener(TimerEvent.TIMER, invoker);
			}
			for each(var thread:Thread in g_list){
				if(thread) thread.Destory();
			}
		}
		
		public function IsInterrupt(): Boolean
		{
			return m_interrupt;
		}
		
		public function SetDeley($millisecond:uint): void
		{
			g_executor.delay = $millisecond;
		}
		
		public function GetName(): String { return m_name; }
		
		public function SetName($name:String): void
		{
			if(m_name) g_table[m_name] = null;
			m_name = $name;
			g_table[m_name] = this;
		}
	}
}